package com.bt7274.service.impl;

import com.bt7274.enums.PermissionGroupEnum;
import com.bt7274.exception.BusinessException;
import com.bt7274.mapper.InvitationCodeMapper;
import com.bt7274.mapper.PermissionMapper;
import com.bt7274.mapper.UserMapper;
import com.bt7274.pojo.InvitationCode;
import com.bt7274.pojo.User;
import com.bt7274.pojo.vo.InvitationCodeVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.bt7274.exception.GraceExceptionHandler.log;

/**
 * 邀请码服务实现类
 */
@Service
public class InvitationCodeServiceImpl implements com.bt7274.service.InvitationCodeService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    private static final String INVITATION_CODE_CHARS
            = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    private static final int CODE_LENGTH = 16;
    private final SecureRandom random = new SecureRandom();
    @Autowired
    private InvitationCodeMapper invitationCodeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public InvitationCode generateInvitationCode(String createBy, Integer expiresHours) {
        // 判断是否有权限生成邀请码
        if (!canGenerateInvitationCode(createBy)){
            throw new BusinessException("权限不足，无法生成邀请码");
        }

        //生成邀请码
        String code = generateUniqueCode();

        // 设置过期时间（默认为2天）
        if(expiresHours == null || expiresHours < 0){
            expiresHours = 48;
        }
        LocalDateTime expiresTime = LocalDateTime.now().plusHours(expiresHours);

        // 创建邀请码实体
        InvitationCode invitationCode = new InvitationCode();
        invitationCode.setId(UUID.randomUUID().toString().replace("-", ""));
        invitationCode.setCode(code);
        invitationCode.setExpiresTime(expiresTime);
        invitationCode.setCreateBy(createBy);
        invitationCode.setCreateTime(LocalDateTime.now());

        // 保存邀请码
        invitationCodeMapper.insert(invitationCode);

        log.info("生成邀请码成功，创建着：{}，邀请码：{}", createBy, code);
        return invitationCode;
    }

    @Override
    public List<InvitationCodeVO> getUserInvitationCodes(String createBy){
        List<InvitationCode> invitationCodes = invitationCodeMapper.selectByCreateBy(createBy);
        return invitationCodes.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    @Override
    public boolean validateInvitationCode(String code) {
        if (!StringUtils.hasText(code)) {
            return false;
        }
        InvitationCode invitationCode = invitationCodeMapper.selectValidCode(code, LocalDateTime.now());
        return invitationCode != null && !StringUtils.hasText(invitationCode.getUsedBy());
    }

    @Override
    public InvitationCode getByCode(String code) {
        return invitationCodeMapper.selectByCode(code);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean useInvitationCode(String code, String usedBy) {
        if (!validateInvitationCode(code)) {
            throw new BusinessException("邀请码无效或已过期");
        }

        //获取邀请码信息
        InvitationCode invitationCode = invitationCodeMapper.selectByCode(code);
        if (invitationCode == null) {
            throw new BusinessException("邀请码不存在");
        }

        //标记为已使用
        return invitationCodeMapper.markAsUsed(invitationCode.getId(), usedBy) > 0;
    }

    @Override
    public int cleanExpiredCodes() {
        return invitationCodeMapper.deleteExpiredCodes(LocalDateTime.now());
    }

    @Override
    public boolean canGenerateInvitationCode(String userId){
        User user = userMapper.selectById(userId);
        if (user == null) {
            return false;
        }
        return user.getPermissionGroup() >= PermissionGroupEnum.FAMOUS_DRIVER.getCode();
    }

    /**
     * 生成唯一邀请码
     *
     * @return String
     * @author galland
     */
    private String generateUniqueCode() {
        String code;
        do {
            code = generateRandomCode();
        } while (invitationCodeMapper.selectByCode(code) != null);
        return code;
    }

    private String generateRandomCode() {
        StringBuilder code = new StringBuilder(CODE_LENGTH);
        for (int i = 0; i < CODE_LENGTH; i++) {
            code.append(INVITATION_CODE_CHARS.charAt(random.nextInt(INVITATION_CODE_CHARS.length())));
        }
        return code.toString();
    }

    private InvitationCodeVO convertToVO(InvitationCode invitationCode) {
        InvitationCodeVO invitationCodeVO = new InvitationCodeVO();
        BeanUtils.copyProperties(invitationCode, invitationCodeVO);
        invitationCodeVO.setIsUsed(StringUtils.hasText(invitationCode.getUsedBy()));
        invitationCodeVO.setIsExpired(invitationCode.getExpiresTime().isBefore(LocalDateTime.now()));

        // 若已使用则获取使用者信息
        if (invitationCodeVO.getIsUsed() && StringUtils.hasText(invitationCode.getUsedBy())) {
            User user = userMapper.selectById(invitationCode.getUsedBy());
            if (user == null) {
                invitationCodeVO.setUsedByUsername(user.getUsername());
            }
        }
        return invitationCodeVO;
    }

}
